package grex.Graphics;

import grex.ErrorManagement.EvolutionListener;
import grex.*;

import grex.Nodes.GeneException;
import java.awt.BorderLayout;

import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;

import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;

import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;

public class PerformancePanel extends JPanel implements EvolutionListener, ActionListener {

    private double totalGenerations;
    int FITNESS = 0, AVG_FITNESS = 1, LENGTH = 2, AVG_LENGTH = 3, TRAIN_ACC = 4, TEST_ACC = 5, TRAIN_AUC = 6, TEST_AUC = 7, NR_OF_STATS = 5;
    Color[] colors = new Color[NR_OF_STATS];
    ArrayList<ArrayList<Double>> statistics;
    String[] names = {"TrainError:", "AvgFitness:", "Length:", "AvgLength:", "TestError:", "TestACC:", "TrainAUC:", "TestAUC:"};
    JCheckBox[] boxes = new JCheckBox[NR_OF_STATS];
    boolean IS_CLASSIFICATION = true;

    public PerformancePanel() {
        super();
       // setBackground(new java.awt.Color(227, 227, 227));
      //  setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED), "Fitness vs. Size"));

        colors[FITNESS] = new Color(150, 255, 150);
        colors[LENGTH] = Color.YELLOW;
        colors[TRAIN_ACC] = Color.RED;
       // colors[TEST_ACC] = Color.RED;
        colors[AVG_FITNESS] = Color.GREEN;
        colors[AVG_LENGTH] = Color.ORANGE;
      //  colors[TRAIN_AUC] = new Color(175, 175, 255);
      //  colors[TEST_AUC] = new Color(75, 75, 255);
        setBackground(Color.BLACK);
        this.setLayout(new BorderLayout());
        JPanel pnlBoxes = new JPanel();
        pnlBoxes.setLayout(new FlowLayout(FlowLayout.CENTER));
        //pnlBoxes.setLayout(new BoxLayout(pnlBoxes, BoxLayout.PAGE_AXIS));
        add(pnlBoxes, BorderLayout.SOUTH);

        for (int line = 0; line < NR_OF_STATS; line++) {
            boxes[line] = new JCheckBox(names[line]);
            boxes[line].setBackground(colors[line]);
            boxes[line].addActionListener(this);
            pnlBoxes.add(boxes[line]);

        }

        boxes[FITNESS].setSelected(true);
        boxes[AVG_FITNESS].setSelected(false);
        boxes[LENGTH].setSelected(true);
        boxes[AVG_LENGTH].setSelected(false);
        boxes[TRAIN_ACC].setSelected(true);
   //     boxes[TEST_ACC].setSelected(true);

        statistics = new ArrayList<ArrayList<Double>>();
        for (int i = 0; i < NR_OF_STATS; i++) {
            statistics.add(new ArrayList<Double>());
        }

    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        double points = statistics.get(0).size();
        if (points > 0) {
            NumberFormat nf = NumberFormat.getInstance();
            nf.setMaximumFractionDigits(1);
            nf.setMinimumFractionDigits(1);
            int boxHeight = boxes[0].getHeight();
            int h = getHeight() - boxHeight;
            double xScale = totalGenerations / (double) getWidth();
            double yScale = 100.0 / h;
            int x1 = 0, x2 = 0, y1 = 0, y2 = 0;

            for (int line = 0; line < NR_OF_STATS; line++) {
                double value = statistics.get(line).get((int) points - 1);
                String val = nf.format(value);
                boxes[line].setText(names[line] + val);

                if (points > 1 && boxes[line].isSelected()) {
                    for (int x = 1; x < points; x++) {

                        g.setColor(colors[line]);
                        x1 = (int) ((x - 1) / xScale);
                        y1 = (int) (statistics.get(line).get(x - 1) / yScale) + boxHeight / 2;
                        x2 = (int) (x / xScale);
                        y2 = (int) (statistics.get(line).get(x) / yScale) + boxHeight / 2;

                        g.drawLine(x1, h-y1, x2, h-y2);
                    }
                    g.drawString(val, x2, h-y2);

                }
            }
        }
    }

    public void evolutionStarted(EvolutionProcess source) {
    }

    public void generationTerminated(EvolutionProcess source) {
        GP gp = (GP) source.getBestGP();//.clone();
        totalGenerations = source.getOptions().getGENERATIONS();

            
            statistics.get(LENGTH).add(gp.getNrOfNodes());
        try {
            statistics.get(FITNESS).add(gp.calcTrainError());
            statistics.get(TRAIN_ACC).add(gp.calcTestError());
        } catch (GeneException ex) {
            Logger.getLogger(PerformancePanel.class.getName()).log(Level.SEVERE, null, ex);
        } catch (BNFException ex) {
            Logger.getLogger(PerformancePanel.class.getName()).log(Level.SEVERE, null, ex);
        }
        /*    statistics.get(TEST_ACC).add(100 - gp.getTestAccError());
            statistics.get(TRAIN_AUC).add(100 - gp.getTrainAUCError());
            statistics.get(TEST_AUC).add(100 - gp.getTestAUCError());*/
            statistics.get(AVG_FITNESS).add(source.getAverageFitness());
            statistics.get(AVG_LENGTH).add(source.getAverageLength());

        this.repaint();
    }

    public void batchTerminated(EvolutionProcess source) {
    }

    public void evolutionTerminated(EvolutionProcess source) {
        source.removeEvolutionLister(this);
    }

    public void evolutionProcessTerminated(EvolutionProcess source) {
    }

    public void actionPerformed(ActionEvent e) {
        repaint();
    }
}
